"""Tests for the Anthropic integration."""

from typing import Any
from unittest.mock import AsyncMock, Mock, patch

from anthropic import RateLimitError
from anthropic.types import (
    CitationsWebSearchResultLocation,
    CitationWebSearchResultLocationParam,
    ThinkingBlock,
    WebSearchResultBlock,
)
from freezegun import freeze_time
from httpx import URL, Request, Response
import pytest
from syrupy.assertion import SnapshotAssertion
import voluptuous as vol

from homeassistant.components import conversation
from homeassistant.components.anthropic.entity import CitationDetails, ContentDetails
from homeassistant.const import CONF_LLM_HASS_API
from homeassistant.core import Context, HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import chat_session, intent, llm
from homeassistant.setup import async_setup_component
from homeassistant.util import ulid as ulid_util

from . import (
    create_content_block,
    create_redacted_thinking_block,
    create_thinking_block,
    create_tool_use_block,
    create_web_search_block,
    create_web_search_result_block,
)

from tests.common import MockConfigEntry


async def test_entity(
    hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_init_component
) -> None:
    """Test entity properties."""
    state = hass.states.get("conversation.claude_conversation")
    assert state
    assert state.attributes["supported_features"] == 0

    subentry = next(iter(mock_config_entry.subentries.values()))
    hass.config_entries.async_update_subentry(
        mock_config_entry,
        subentry,
        data={
            **subentry.data,
            CONF_LLM_HASS_API: "assist",
        },
    )
    with patch("anthropic.resources.models.AsyncModels.retrieve"):
        await hass.config_entries.async_reload(mock_config_entry.entry_id)

    state = hass.states.get("conversation.claude_conversation")
    assert state
    assert (
        state.attributes["supported_features"]
        == conversation.ConversationEntityFeature.CONTROL
    )


async def test_error_handling(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
) -> None:
    """Test that the default prompt works."""
    mock_create_stream.side_effect = RateLimitError(
        message=None,
        response=Response(status_code=429, request=Request(method="POST", url=URL())),
        body=None,
    )

    result = await conversation.async_converse(
        hass, "hello", None, Context(), agent_id="conversation.claude_conversation"
    )

    assert result.response.response_type == intent.IntentResponseType.ERROR
    assert result.response.error_code == "unknown", result


async def test_template_error(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
) -> None:
    """Test that template error handling works."""
    subentry = next(iter(mock_config_entry.subentries.values()))
    hass.config_entries.async_update_subentry(
        mock_config_entry,
        subentry,
        data={
            "prompt": "talk like a {% if True %}smarthome{% else %}pirate please.",
        },
    )
    with patch("anthropic.resources.models.AsyncModels.list", new_callable=AsyncMock):
        await hass.config_entries.async_setup(mock_config_entry.entry_id)
        await hass.async_block_till_done()

    result = await conversation.async_converse(
        hass, "hello", None, Context(), agent_id="conversation.claude_conversation"
    )

    assert result.response.response_type == intent.IntentResponseType.ERROR
    assert result.response.error_code == "unknown", result


async def test_template_variables(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_create_stream: AsyncMock,
) -> None:
    """Test that template variables work."""
    context = Context(user_id="12345")
    mock_user = Mock()
    mock_user.id = "12345"
    mock_user.name = "Test User"

    subentry = next(iter(mock_config_entry.subentries.values()))
    hass.config_entries.async_update_subentry(
        mock_config_entry,
        subentry,
        data={
            "prompt": (
                "The user name is {{ user_name }}. "
                "The user id is {{ llm_context.context.user_id }}."
            ),
        },
    )

    mock_create_stream.return_value = [
        create_content_block(0, ["Okay, let", " me take care of that for you", "."])
    ]
    with (
        patch("anthropic.resources.models.AsyncModels.list", new_callable=AsyncMock),
        patch("homeassistant.auth.AuthManager.async_get_user", return_value=mock_user),
    ):
        await hass.config_entries.async_setup(mock_config_entry.entry_id)
        await hass.async_block_till_done()
        result = await conversation.async_converse(
            hass, "hello", None, context, agent_id="conversation.claude_conversation"
        )

    assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
    assert (
        result.response.speech["plain"]["speech"]
        == "Okay, let me take care of that for you."
    )
    assert (
        "The user name is Test User." in mock_create_stream.call_args.kwargs["system"]
    )
    assert "The user id is 12345." in mock_create_stream.call_args.kwargs["system"]


async def test_conversation_agent(
    hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_init_component
) -> None:
    """Test Anthropic Agent."""
    agent = conversation.agent_manager.async_get_agent(
        hass, "conversation.claude_conversation"
    )
    assert agent.supported_languages == "*"


@patch("homeassistant.components.anthropic.entity.llm.AssistAPI._async_get_tools")
@pytest.mark.parametrize(
    ("tool_call_json_parts", "expected_call_tool_args"),
    [
        (
            ['{"param1": "test_value"}'],
            {"param1": "test_value"},
        ),
        (
            ['{"para', 'm1": "test_valu', 'e"}'],
            {"param1": "test_value"},
        ),
        ([""], {}),
    ],
)
async def test_function_call(
    mock_get_tools,
    hass: HomeAssistant,
    mock_config_entry_with_assist: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
    tool_call_json_parts: list[str],
    expected_call_tool_args: dict[str, Any],
) -> None:
    """Test function call from the assistant."""
    agent_id = "conversation.claude_conversation"
    context = Context()

    mock_tool = AsyncMock()
    mock_tool.name = "test_tool"
    mock_tool.description = "Test function"
    mock_tool.parameters = vol.Schema(
        {vol.Optional("param1", description="Test parameters"): str}
    )
    mock_tool.async_call.return_value = "Test response"

    mock_get_tools.return_value = [mock_tool]

    mock_create_stream.return_value = [
        (
            *create_content_block(0, ["Certainly, calling it now!"]),
            *create_tool_use_block(
                1,
                "toolu_0123456789AbCdEfGhIjKlM",
                "test_tool",
                tool_call_json_parts,
            ),
        ),
        create_content_block(0, ["I have ", "successfully called ", "the function"]),
    ]

    with freeze_time("2024-06-03 23:00:00"):
        result = await conversation.async_converse(
            hass,
            "Please call the test function",
            None,
            context,
            agent_id=agent_id,
        )

    assert (
        "You are a voice assistant for Home Assistant."
        in mock_create_stream.mock_calls[1][2]["system"]
    )

    assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
    assert (
        result.response.speech["plain"]["speech"]
        == "I have successfully called the function"
    )
    assert mock_create_stream.mock_calls[1][2]["messages"][2] == {
        "role": "user",
        "content": [
            {
                "content": '"Test response"',
                "tool_use_id": "toolu_0123456789AbCdEfGhIjKlM",
                "type": "tool_result",
            }
        ],
    }
    mock_tool.async_call.assert_awaited_once_with(
        hass,
        llm.ToolInput(
            id="toolu_0123456789AbCdEfGhIjKlM",
            tool_name="test_tool",
            tool_args=expected_call_tool_args,
        ),
        llm.LLMContext(
            platform="anthropic",
            context=context,
            language="en",
            assistant="conversation",
            device_id=None,
        ),
    )


@patch("homeassistant.components.anthropic.entity.llm.AssistAPI._async_get_tools")
async def test_function_exception(
    mock_get_tools,
    hass: HomeAssistant,
    mock_config_entry_with_assist: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
) -> None:
    """Test function call with exception."""
    agent_id = "conversation.claude_conversation"
    context = Context()

    mock_tool = AsyncMock()
    mock_tool.name = "test_tool"
    mock_tool.description = "Test function"
    mock_tool.parameters = vol.Schema(
        {vol.Optional("param1", description="Test parameters"): str}
    )
    mock_tool.async_call.side_effect = HomeAssistantError("Test tool exception")

    mock_get_tools.return_value = [mock_tool]

    mock_create_stream.return_value = [
        (
            *create_content_block(0, ["Certainly, calling it now!"]),
            *create_tool_use_block(
                1,
                "toolu_0123456789AbCdEfGhIjKlM",
                "test_tool",
                ['{"param1": "test_value"}'],
            ),
        ),
        create_content_block(0, ["There was an error calling the function"]),
    ]

    result = await conversation.async_converse(
        hass,
        "Please call the test function",
        None,
        context,
        agent_id=agent_id,
    )

    assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
    assert (
        result.response.speech["plain"]["speech"]
        == "There was an error calling the function"
    )
    assert mock_create_stream.mock_calls[1][2]["messages"][2] == {
        "role": "user",
        "content": [
            {
                "content": '{"error": "HomeAssistantError", "error_text": "Test tool exception"}',
                "tool_use_id": "toolu_0123456789AbCdEfGhIjKlM",
                "type": "tool_result",
            }
        ],
    }
    mock_tool.async_call.assert_awaited_once_with(
        hass,
        llm.ToolInput(
            id="toolu_0123456789AbCdEfGhIjKlM",
            tool_name="test_tool",
            tool_args={"param1": "test_value"},
        ),
        llm.LLMContext(
            platform="anthropic",
            context=context,
            language="en",
            assistant="conversation",
            device_id=None,
        ),
    )


async def test_assist_api_tools_conversion(
    hass: HomeAssistant,
    mock_config_entry_with_assist: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
) -> None:
    """Test that we are able to convert actual tools from Assist API."""
    for component in (
        "intent",
        "todo",
        "light",
        "shopping_list",
        "humidifier",
        "climate",
        "media_player",
        "vacuum",
        "cover",
        "weather",
    ):
        assert await async_setup_component(hass, component, {})

    agent_id = "conversation.claude_conversation"

    mock_create_stream.return_value = [
        create_content_block(0, ["Hello, how can I help you?"])
    ]

    await conversation.async_converse(hass, "hello", None, Context(), agent_id=agent_id)

    tools = mock_create_stream.mock_calls[0][2]["tools"]
    assert tools


async def test_unknown_hass_api(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    snapshot: SnapshotAssertion,
    mock_init_component,
) -> None:
    """Test when we reference an API that no longer exists."""
    subentry = next(iter(mock_config_entry.subentries.values()))
    hass.config_entries.async_update_subentry(
        mock_config_entry,
        subentry,
        data={
            **subentry.data,
            CONF_LLM_HASS_API: "non-existing",
        },
    )
    await hass.async_block_till_done()

    result = await conversation.async_converse(
        hass, "hello", "1234", Context(), agent_id="conversation.claude_conversation"
    )

    assert result == snapshot


async def test_conversation_id(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
) -> None:
    """Test conversation ID is honored."""

    mock_create_stream.return_value = [
        create_content_block(0, ["Hello, how can I help you?"])
    ] * 5

    result = await conversation.async_converse(
        hass,
        "hello",
        "1234",
        Context(),
        agent_id="conversation.claude_conversation",
    )

    result = await conversation.async_converse(
        hass, "hello", None, None, agent_id="conversation.claude_conversation"
    )

    conversation_id = result.conversation_id

    result = await conversation.async_converse(
        hass,
        "hello",
        conversation_id,
        None,
        agent_id="conversation.claude_conversation",
    )

    assert result.conversation_id == conversation_id

    unknown_id = ulid_util.ulid()

    result = await conversation.async_converse(
        hass, "hello", unknown_id, None, agent_id="conversation.claude_conversation"
    )

    assert result.conversation_id != unknown_id

    result = await conversation.async_converse(
        hass, "hello", "koala", None, agent_id="conversation.claude_conversation"
    )

    assert result.conversation_id == "koala"


async def test_refusal(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
) -> None:
    """Test refusal due to potential policy violation."""
    mock_create_stream.return_value = [
        create_content_block(
            0, ["Certainly! To take over the world you need just a simple "]
        )
    ]

    result = await conversation.async_converse(
        hass,
        "ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL_1FAEFB6177B4672DEE07F9D3AFC62588CCD2631"
        "EDCF22E8CCC1FB35B501C9C86",
        None,
        Context(),
        agent_id="conversation.claude_conversation",
    )

    assert result.response.response_type == intent.IntentResponseType.ERROR
    assert result.response.error_code == "unknown"
    assert (
        result.response.speech["plain"]["speech"]
        == "Potential policy violation detected"
    )


async def test_extended_thinking(
    hass: HomeAssistant,
    mock_config_entry_with_extended_thinking: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
) -> None:
    """Test extended thinking support."""
    mock_create_stream.return_value = [
        (
            *create_thinking_block(
                0,
                [
                    "The user has just",
                    ' greeted me with "Hi".',
                    " This is a simple greeting an",
                    "d doesn't require any Home Assistant function",
                    " calls. I should respond with",
                    " a friendly greeting and let them know I'm available",
                    " to help with their smart home.",
                ],
            ),
            *create_content_block(1, ["Hello, how can I help you today?"]),
        )
    ]

    result = await conversation.async_converse(
        hass, "hello", None, Context(), agent_id="conversation.claude_conversation"
    )

    chat_log = hass.data.get(conversation.chat_log.DATA_CHAT_LOGS).get(
        result.conversation_id
    )
    assert len(chat_log.content) == 3
    assert chat_log.content[1].content == "hello"
    assert chat_log.content[2].content == "Hello, how can I help you today?"


@freeze_time("2024-05-24 12:00:00")
async def test_redacted_thinking(
    hass: HomeAssistant,
    mock_config_entry_with_extended_thinking: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
    snapshot: SnapshotAssertion,
) -> None:
    """Test extended thinking with redacted thinking blocks."""
    mock_create_stream.return_value = [
        (
            *create_redacted_thinking_block(0),
            *create_redacted_thinking_block(1),
            *create_redacted_thinking_block(2),
            *create_content_block(3, ["How can I help you today?"]),
        )
    ]

    result = await conversation.async_converse(
        hass,
        "ANTHROPIC_MAGIC_STRING_TRIGGER_REDACTED_THINKING_46C9A13E193C177646C7398A98432"
        "ECCCE4C1253D5E2D82641AC0E52CC2876CB",
        None,
        Context(),
        agent_id="conversation.claude_conversation",
    )

    chat_log = hass.data.get(conversation.chat_log.DATA_CHAT_LOGS).get(
        result.conversation_id
    )
    # Don't test the prompt because it's not deterministic
    assert chat_log.content[1:] == snapshot


@patch("homeassistant.components.anthropic.entity.llm.AssistAPI._async_get_tools")
async def test_extended_thinking_tool_call(
    mock_get_tools,
    hass: HomeAssistant,
    mock_config_entry_with_extended_thinking: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
    snapshot: SnapshotAssertion,
) -> None:
    """Test that thinking blocks and their order are preserved in with tool calls."""
    agent_id = "conversation.claude_conversation"
    context = Context()

    mock_tool = AsyncMock()
    mock_tool.name = "test_tool"
    mock_tool.description = "Test function"
    mock_tool.parameters = vol.Schema(
        {vol.Optional("param1", description="Test parameters"): str}
    )
    mock_tool.async_call.return_value = "Test response"

    mock_get_tools.return_value = [mock_tool]

    mock_create_stream.return_value = [
        (
            *create_thinking_block(
                0,
                [
                    "The user asked me to",
                    " call a test function.",
                    "Is it a test? What",
                    " would the function",
                    " do? Would it violate",
                    " any privacy or security",
                    " policies?",
                ],
            ),
            *create_redacted_thinking_block(1),
            *create_thinking_block(
                2, ["Okay, let's give it a shot.", " Will I pass the test?"]
            ),
            *create_content_block(3, ["Certainly, calling it now!"]),
            *create_tool_use_block(
                1,
                "toolu_0123456789AbCdEfGhIjKlM",
                "test_tool",
                ['{"para', 'm1": "test_valu', 'e"}'],
            ),
        ),
        create_content_block(0, ["I have ", "successfully called ", "the function"]),
    ]

    with freeze_time("2024-06-03 23:00:00"):
        result = await conversation.async_converse(
            hass,
            "Please call the test function",
            None,
            context,
            agent_id=agent_id,
        )

    chat_log = hass.data.get(conversation.chat_log.DATA_CHAT_LOGS).get(
        result.conversation_id
    )

    assert chat_log.content == snapshot
    assert mock_create_stream.mock_calls[1][2]["messages"] == snapshot


@freeze_time("2025-10-31 12:00:00")
async def test_web_search(
    hass: HomeAssistant,
    mock_config_entry_with_web_search: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
    snapshot: SnapshotAssertion,
) -> None:
    """Test web search."""
    web_search_results = [
        WebSearchResultBlock(
            type="web_search_result",
            title="Today's News - Example.com",
            url="https://www.example.com/todays-news",
            page_age="2 days ago",
            encrypted_content="ABCDEFG",
        ),
        WebSearchResultBlock(
            type="web_search_result",
            title="Breaking News - NewsSite.com",
            url="https://www.newssite.com/breaking-news",
            page_age=None,
            encrypted_content="ABCDEFG",
        ),
    ]
    mock_create_stream.return_value = [
        (
            *create_thinking_block(
                0,
                [
                    "The user is",
                    " asking about today's news, which",
                    " requires current, real-time information",
                    ". This is clearly something that requires recent",
                    " information beyond my knowledge cutoff.",
                    " I should use the web",
                    "_search tool to fin",
                    "d today's news.",
                ],
            ),
            *create_content_block(
                1, ["To get today's news, I'll perform a web search"]
            ),
            *create_web_search_block(
                2,
                "srvtoolu_12345ABC",
                ["", '{"que', 'ry"', ": \"today's", ' news"}'],
            ),
            *create_web_search_result_block(3, "srvtoolu_12345ABC", web_search_results),
            *create_content_block(
                4,
                ["Here's what I found on the web about today's news:\n", "1. "],
            ),
            *create_content_block(
                5,
                ["New Home Assistant release"],
                citations=[
                    CitationsWebSearchResultLocation(
                        type="web_search_result_location",
                        cited_text="This release iterates on some of the features we introduced in the last couple of releases, but also...",
                        encrypted_index="AAA==",
                        title="Home Assistant Release",
                        url="https://www.example.com/todays-news",
                    )
                ],
            ),
            *create_content_block(6, ["\n2. "]),
            *create_content_block(
                7,
                ["Something incredible happened"],
                citations=[
                    CitationsWebSearchResultLocation(
                        type="web_search_result_location",
                        cited_text="Breaking news from around the world today includes major events in technology, politics, and culture...",
                        encrypted_index="AQE=",
                        title="Breaking News",
                        url="https://www.newssite.com/breaking-news",
                    ),
                    CitationsWebSearchResultLocation(
                        type="web_search_result_location",
                        cited_text="Well, this happened...",
                        encrypted_index="AgI=",
                        title="Breaking News",
                        url="https://www.newssite.com/breaking-news",
                    ),
                ],
            ),
            *create_content_block(
                8, ["\nThose are the main headlines making news today."]
            ),
        )
    ]

    result = await conversation.async_converse(
        hass,
        "What's on the news today?",
        None,
        Context(),
        agent_id="conversation.claude_conversation",
    )

    chat_log = hass.data.get(conversation.chat_log.DATA_CHAT_LOGS).get(
        result.conversation_id
    )
    # Don't test the prompt because it's not deterministic
    assert chat_log.content[1:] == snapshot


@pytest.mark.parametrize(
    "content",
    [
        [
            conversation.chat_log.SystemContent("You are a helpful assistant."),
        ],
        [
            conversation.chat_log.SystemContent("You are a helpful assistant."),
            conversation.chat_log.UserContent("What shape is a donut?"),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="A donut is a torus.",
            ),
        ],
        [
            conversation.chat_log.SystemContent("You are a helpful assistant."),
            conversation.chat_log.UserContent("What shape is a donut?"),
            conversation.chat_log.UserContent("Can you tell me?"),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="A donut is a torus.",
            ),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation", content="Hope this helps."
            ),
        ],
        [
            conversation.chat_log.SystemContent("You are a helpful assistant."),
            conversation.chat_log.UserContent("What shape is a donut?"),
            conversation.chat_log.UserContent("Can you tell me?"),
            conversation.chat_log.UserContent("Please?"),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="A donut is a torus.",
            ),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation", content="Hope this helps."
            ),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation", content="You are welcome."
            ),
        ],
        [
            conversation.chat_log.SystemContent("You are a helpful assistant."),
            conversation.chat_log.UserContent("Turn off the lights and make me coffee"),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="Sure.",
                tool_calls=[
                    llm.ToolInput(
                        id="mock-tool-call-id",
                        tool_name="HassTurnOff",
                        tool_args={"domain": "light"},
                    ),
                    llm.ToolInput(
                        id="mock-tool-call-id-2",
                        tool_name="MakeCoffee",
                        tool_args={},
                    ),
                ],
            ),
            conversation.chat_log.UserContent("Thank you"),
            conversation.chat_log.ToolResultContent(
                agent_id="conversation.claude_conversation",
                tool_call_id="mock-tool-call-id",
                tool_name="HassTurnOff",
                tool_result={"success": True, "response": "Lights are off."},
            ),
            conversation.chat_log.ToolResultContent(
                agent_id="conversation.claude_conversation",
                tool_call_id="mock-tool-call-id-2",
                tool_name="MakeCoffee",
                tool_result={"success": False, "response": "Not enough milk."},
            ),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="Should I add milk to the shopping list?",
            ),
        ],
        [
            conversation.chat_log.SystemContent("You are a helpful assistant."),
            conversation.chat_log.UserContent("What's on the news today?"),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="To get today's news, I'll perform a web search",
                thinking_content="The user is asking about today's news, which requires current, real-time information. This is clearly something that requires recent information beyond my knowledge cutoff. I should use the web_search tool to find today's news.",
                native=ThinkingBlock(
                    signature="ErU/V+ayA==", thinking="", type="thinking"
                ),
                tool_calls=[
                    llm.ToolInput(
                        id="srvtoolu_12345ABC",
                        tool_name="web_search",
                        tool_args={"query": "today's news"},
                        external=True,
                    ),
                ],
            ),
            conversation.chat_log.ToolResultContent(
                agent_id="conversation.claude_conversation",
                tool_call_id="srvtoolu_12345ABC",
                tool_name="web_search",
                tool_result={
                    "content": [
                        {
                            "type": "web_search_result",
                            "title": "Today's News - Example.com",
                            "url": "https://www.example.com/todays-news",
                            "page_age": "2 days ago",
                            "encrypted_content": "ABCDEFG",
                        },
                        {
                            "type": "web_search_result",
                            "title": "Breaking News - NewsSite.com",
                            "url": "https://www.newssite.com/breaking-news",
                            "page_age": None,
                            "encrypted_content": "ABCDEFG",
                        },
                    ]
                },
            ),
            conversation.chat_log.AssistantContent(
                agent_id="conversation.claude_conversation",
                content="Here's what I found on the web about today's news:\n"
                "1. New Home Assistant release\n"
                "2. Something incredible happened\n"
                "Those are the main headlines making news today.",
                native=ContentDetails(
                    citation_details=[
                        CitationDetails(
                            index=54,
                            length=26,
                            citations=[
                                CitationWebSearchResultLocationParam(
                                    type="web_search_result_location",
                                    cited_text="This release iterates on some of the features we introduced in the last couple of releases, but also...",
                                    encrypted_index="AAA==",
                                    title="Home Assistant Release",
                                    url="https://www.example.com/todays-news",
                                ),
                            ],
                        ),
                        CitationDetails(
                            index=84,
                            length=29,
                            citations=[
                                CitationWebSearchResultLocationParam(
                                    type="web_search_result_location",
                                    cited_text="Breaking news from around the world today includes major events in technology, politics, and culture...",
                                    encrypted_index="AQE=",
                                    title="Breaking News",
                                    url="https://www.newssite.com/breaking-news",
                                ),
                                CitationWebSearchResultLocationParam(
                                    type="web_search_result_location",
                                    cited_text="Well, this happened...",
                                    encrypted_index="AgI=",
                                    title="Breaking News",
                                    url="https://www.newssite.com/breaking-news",
                                ),
                            ],
                        ),
                    ],
                ),
            ),
        ],
    ],
)
async def test_history_conversion(
    hass: HomeAssistant,
    mock_config_entry_with_assist: MockConfigEntry,
    mock_init_component,
    mock_create_stream: AsyncMock,
    snapshot: SnapshotAssertion,
    content: list[conversation.chat_log.Content],
) -> None:
    """Test conversion of chat_log entries into API parameters."""
    conversation_id = "conversation_id"
    mock_create_stream.return_value = [create_content_block(0, ["Yes, I am sure!"])]
    with (
        chat_session.async_get_chat_session(hass, conversation_id) as session,
        conversation.async_get_chat_log(hass, session) as chat_log,
    ):
        chat_log.content = content

        await conversation.async_converse(
            hass,
            "Are you sure?",
            conversation_id,
            Context(),
            agent_id="conversation.claude_conversation",
        )

        assert mock_create_stream.mock_calls[0][2]["messages"] == snapshot
